Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow generic type parameters for custom extensions #3230

Closed
wants to merge 1 commit into from

Conversation

Cipscis
Copy link

@Cipscis Cipscis commented Mar 15, 2024

Marked version: 11.1.0

Markdown flavor: n/a

Description

This PR adds optional generic type parameters to the types used for creating custom extensions. This allows marked to communicate more specific expectations to TypeScript for the token returned by a custom tokenizer function, and for the token passed to a custom renderer function.

Example usage:

const myCustomExtension: TokenizerAndRendererExtension<
  'myCustomExtension',
  { example: string }
> = {
  name: 'myCustomExtension',
  level: 'inline',
  start(src) {
    // ...
  },
  tokenizer(src, tokens) {
    // ...

    return {
      type: 'myCustomExtension',
      raw: src,
      example: 'must be a string',
      tokens: [],
    };
  },
  renderer(token) {
    token.type; // <- 'myCustomExtension'
    token.example; // <- string
    // ...
  },
};

Unfortunately, it's not quite so easy to set this to allow the generic type parameters to be inferred as I had hoped. I'd forgotten when writing the issue that TypeScript is only able to infer generic types in function parameters, so that can't be done with type updates alone.

Enabling this sort of type inference would require a noop function wrapper to allow TypeScript to do inference, and I'm not sure if that would be a useful addition to marked's API:

function createExtension<
  N extends string = string,
  T extends Record<string, unknown> = Record<string, any>
>(extension: TokenizerAndRendererExtension<N, T>): TokenizerAndRendererExtension<N, T> {
  return extension;
}

const myCustomExtension = createExtension({
  // extension code as in previous example
});
// ^ TokenizerAndRendererExtension<"myCustomExtension", {
//   type: "myCustomExtension";
//   raw: string;
//   example: string;
//   tokens: never[];
// }>

I'm also less certain about how valuable it is to include the name in the generic parameter. Particularly as it's necessary to declare as const if the token is not immediately returned, e.g.

tokenizer(src, tokens) {
  // ...

  const token = {
    type: 'myCustomExtension' as const,
    raw,
    example: 'must be a string',
    tokens: [],
  };
  return token;
},

Because this PR only contains type changes, no actual functionality should have changed. And because the only changes have been adding generic type arguments with defaults that replicate the existing behaviour, I expect there wouldn't be any breaking changes with existing TypeScript code.

I'm not sure where best to document this feature's PR, so currently have not included any new documentation.

Contributor

  • Test(s) exist to ensure functionality and minimize regression (if no tests added, list tests covering this PR); or,
  • no tests required for this PR.
  • If submitting new feature, it has been documented in the appropriate places.

Committer

In most cases, this should be a different person than the contributor.

Copy link

vercel bot commented Mar 15, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
marked-website ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 15, 2024 8:24am

@UziTech
Copy link
Member

UziTech commented Mar 16, 2024

@UziTech
Copy link
Member

UziTech commented Aug 26, 2024

@Cipscis are you still working on this?

@Cipscis
Copy link
Author

Cipscis commented Aug 30, 2024

Sorry, no I haven't touched it since March

@UziTech
Copy link
Member

UziTech commented Sep 4, 2024

I'm going to close this as stale. If you would like to continue working on this feel free to open it.

@UziTech UziTech closed this Sep 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improved TypeScript types for TokenizerAndRendererExtension
2 participants